#include <iostream>
#include <cassert>
#include "fmb.h"

using namespace std;
using namespace fm::base;

class A {
private:
  static int NUM_CTOR;
  static int NUM_COPY_CTOR;
  static int NUM_DTOR;
  static int NUM_ASIGMENT;
public:
  A() { ++NUM_CTOR; }
  A(const A& source) { ++NUM_COPY_CTOR; }
  A& operator=(const A& source) { ++NUM_ASIGMENT; return *this; }
  ~A() { ++NUM_DTOR; }

  inline int operator()(int a, int b) { return a + b; }
  inline int mul(int a, int b) { return a * b; }

  static void test() {
    cout << "NUM_CTOR = " << NUM_CTOR << endl;
    cout << "NUM_COPY_CTOR = " << NUM_COPY_CTOR << endl;
    cout << "NUM_DTOR = " << NUM_DTOR << endl;
    cout << "NUM_ASIGMENT = " << NUM_ASIGMENT << endl;
    assert(NUM_CTOR + NUM_COPY_CTOR == NUM_DTOR);
    cout << "OK: NUM_CTOR + NUM_COPY_CTOR = NUM_DTOR" << endl;
  }
};

int A::NUM_CTOR = 0;
int A::NUM_COPY_CTOR = 0;
int A::NUM_DTOR = 0;
int A::NUM_ASIGMENT = 0;

class Base {
public:
  virtual int operator()(int a, int b) = 0;
  virtual ~Base() {}
  virtual Base* clone() const = 0;
};

class Add : public Base {
public:
  Add() {}
  virtual int operator()(int a, int b) { return a + b; }
  virtual ~Add() {}
  virtual Base* clone() const { return new Add(); }
};

class Holder {
private:
  SinglePtr<Base> m_impl;

public:

  Holder(const Base& base) : m_impl(base.clone()) {}

  Holder(const Holder &source) : m_impl(source.m_impl.ptr()->clone()) {
    //Base *b = source.m_ptr.ptr()->clone;
  }

  int foo(int a, int b) {
    return (*m_impl)(a, b);
  }
};

int main(int argc, char **argv) {
  {
    SinglePtr<A> ptr(new A());
    assert(ptr.ptr()->mul(6, 7) == 42);
    cout << "OK: raw pointer getter" << endl;
    assert((*ptr)(1, 2) == 3);
    cout << "OK: dereference operator" << endl;

    Add a = Add();
    Holder h(a);
    Holder h2(h);
    assert(h.foo(4, 5) == 9);
    assert(h.foo(6, 7) == 13);
  }

  A::test();
  cout << "Ptr test done" << endl;

  return 0;
}